#include <iostream>
#include <functional>
#include <vector>

using std::cout;
using std::endl;
using std::bind;
using std::vector;

void display(int x, int y)
{
    cout << x << ", " << y << endl;
}

int test0()
{
    vector<int> numbers{1, 2, 3, 4, 5};
    //普通函数
    //std::placeholders::_1 占位符
    for_each(numbers.begin(), numbers.end(), bind(display, 1, std::placeholders::_1));
    cout << endl;
    return 0;
}

int add(int x, int y)
{
    cout << "x:" << x << endl;
    cout << "y:" << y << endl;
    return x + y;
}

void test1()
{
    //f1是一个函数对象
    auto f1 = std::bind(add, 1, 2);
    cout << f1() << endl;

    //表示的是占位符的命名空间
    using namespace std::placeholders;
    //占位符_1 表示还需要在函数调用时，传递一个参数
    //
    //占位符本身所占的位置是代表形参的位置
    //占位符上的数字所代表的是实参传递时的位置
    auto f2 = std::bind(add, 1, _1);
    cout << f2(10) << endl;
    //因为占位符的数字是3，所以实参传递时需要第三个实参，
    //而实参传递时，前面的第一和第二个实参都变成了无效参数
    auto f3 = std::bind(add, 1, _3);
    cout << f3(10, 20, 30) << endl;
}

struct Foo
{
    int add(int x, int y)
    {
        _data += 10;
        cout << "_data:" << _data << endl;
        cout << "x:" << x << endl;
        cout << "y:" << y << endl;
        return x + y;
    }

    int _data = 100;
};

void test2()
{
    cout << "test2()" << endl;
    Foo foo;
    //使用std::bind时，如果绑定的是非静态的成员函数，则必须要
    //在成员函数名之前加上&符号
    auto f1 = std::bind(&Foo::add, &foo, 1, 2);
    cout << f1() << endl << endl;

    using namespace std::placeholders;
    auto f2 = std::bind(&Foo::add, &foo, 1, _1);
    cout << f2(10) << endl << endl;

    auto f3 = std::bind(&Foo::add, &foo, 1, _2);
    cout << f3(10, 20) << endl << endl;

    auto f4 = std::bind(&Foo::add, &foo, _2, _1);
    cout << f4(10, 20) << endl << endl;

    //绑定了一个数据成员
    auto f5 = std::bind(&Foo::_data, &foo);
    cout << f5() << endl;
}

void test3()
{
    cout << "test3()" << endl;
    Foo foo;
    //使用std::bind时，如果绑定的是非静态的成员函数，则必须要
    //在成员函数名之前加上&符号
    //对于第一个参数是this指针的情况，可以传递对象的地址,
    //但要注意：当函数执行时，对象的生命周期不能结束
    //
    //也可以直接传递对象, 此时会对对象进行复制
    //这说明std::bind的参数绑定采用的是值传递
    auto f1 = std::bind(&Foo::add, foo, 1, 2);
    cout << f1() << endl << endl;

    using namespace std::placeholders;
    auto f2 = std::bind(&Foo::add, foo, 1, _1);
    cout << f2(10) << endl << endl;

    auto f3 = std::bind(&Foo::add, foo, 1, _2);
    cout << f3(10, 20) << endl << endl;

    auto f4 = std::bind(&Foo::add, foo, _2, _1);
    cout << f4(10, 20) << endl << endl;

    //绑定了一个数据成员
    auto f5 = std::bind(&Foo::_data, foo);
    cout << f5() << endl;
    cout << "foo._data:" << foo._data << endl;
}

void print(int x, int & y)
{
    cout << "x:" << x << endl;
    cout << "y:" << y << endl;
}

void test4()
{
    int a = 1, b = 2;
    //a,b的提前绑定， 都是采用值传递进行的
    auto f1 = std::bind(print, a, b);
    //当希望传递引用时，必须要使用引用包装器std::ref
    auto f2 = std::bind(print, a, std::ref(b));
    a = 10;
    b = 20;
    cout << "f1()" << endl;
    f1();//1, 2
    cout << "\nf2()" << endl;
    f2();
}

int main()
{
    /* test0(); */
    /* test2(); */
    /* test3(); */
    test4();
    return 0;
}

